home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / drsi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-21  |  31.1 KB  |  1,106 lines

  1. /*
  2.  * Version with Stopwatches
  3.  *
  4.  * 0 - Not used
  5.  * 1 - rx_fsm run time
  6.  * 2 - drtx_active run time (per character tx time)
  7.  * 
  8.  * Interface driver for the DRSI board for KA9Q's TCP/IP on an IBM-PC ONLY!
  9.  *
  10.  * Derived from a driver written by Art Goldman, WA3CVG
  11.  * (c) Copyright 1987 All Rights Reserved
  12.  * Permission for non-commercial use is hereby granted provided this notice
  13.  * is retained.  For info call: (301) 997-3838.
  14.  *
  15.  * Heavily re-written from the original,  a driver for the EAGLE board into
  16.  * a driver for the DRSI PC* Packet adpator. Copyright as original, all
  17.  * amendments likewise providing credit given and notice retained.
  18.  * Stu Phillips - N6TTO, W6/G8HQA (yes Virginia,  really !).
  19.  * For info call: (408) 285-4142
  20.  *
  21.  * This driver supports 1 (one) DRSI board.
  22.  * 
  23.  * Reformatted and added ANSI-style declarations, integrated into NOS
  24.  * by KA9Q, 10/14/89
  25.  *
  26.  * Latest set of defect fixes added 1/2/90 by N6TTO
  27.  * 1. Made P-PERSIST work properly
  28.  * 2. Fixed UNDERRUN bug when in DEFER state
  29.  * 3. Tx now defers correctly when DCD is high (!)
  30.  *
  31.  * Changed 3/4/90 by N6TTO
  32.  * Changed method of enabling the IRQ to the 8259 to call maskon()
  33.  * instead of clrbit(); change made to allow interrupts > 8 to work
  34.  * on an AT.
  35.  *
  36.  * Changed 11/14/90 by N6TTO
  37.  * Fixed incompatiblity between current NOS memory allocation scheme
  38.  * and changes made to speed up drsi transmit state machine.
  39.  *
  40.  * Added 'fullduplex' channel control parameter in DRSI.H and incorporated
  41.  * minor changes into this piece of code to make it work.
  42.  * FULLDUP == 1 turns off any DCD or persistence control to allow proper
  43.  * DAMA slave operation.
  44.  * DL6ZBA, 09/20/94
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include <dos.h>
  49. #include <time.h>
  50. #include "global.h"
  51. #include "config.h"
  52. #ifdef DRSI
  53. #include "mbuf.h"
  54. #include "iface.h"
  55. #include "pktdrvr.h"
  56. #include "netuser.h"
  57. #include "drsi.h"
  58. #include "ax25.h"
  59. #include "trace.h"
  60. #include "pc.h"
  61. #include "8530.h"
  62.  
  63. static int dr_ctl __ARGS((struct iface *iface,int argc,char *argv[]));
  64. static int dr_raw __ARGS((struct iface *iface,struct mbuf *bp));
  65. static int dr_stop __ARGS((struct iface *iface,int tmp));
  66. static void dr_wake __ARGS((struct drchan *hp,int rx_or_tx,
  67.     void (*routine) __ARGS((struct drchan *)),int ticks));
  68. static int drchanparam __ARGS((struct drchan *hp));
  69. static void drexint __ARGS((struct drchan *hp));
  70. static void drinitctc __ARGS((unsigned port));
  71. static void drrx_active __ARGS((struct drchan *hp));
  72. static void drrx_enable __ARGS((struct drchan *hp));
  73. static void drtx_active __ARGS((struct drchan *hp));
  74. static void drtx_defer __ARGS((struct drchan *hp));
  75. static void drtx_downtx __ARGS((struct drchan *hp));
  76. static void drtx_flagout __ARGS((struct drchan *hp));
  77. static void drtx_idle __ARGS((struct drchan *hp));
  78. static void drtx_rrts __ARGS((struct drchan *hp));
  79. static void drtx_tfirst __ARGS((struct drchan *hp));
  80. static char read_ctc __ARGS((unsigned port,unsigned reg));
  81. static void rx_fsm __ARGS((struct drchan *hp));
  82. static void tx_fsm __ARGS((struct drchan *hp));
  83. static void write_ctc __ARGS((unsigned port,unsigned reg,unsigned val));
  84.  
  85. struct DRTAB Drsi[DRMAX];       /* Device table - one entry per card */
  86. INTERRUPT (*Drhandle[]) __ARGS((void)) = { dr0vec };  /* handler interrupt vector table */
  87. struct drchan Drchan[2*DRMAX];   /* channel table - 2 entries per card */
  88. int16 Drnbr = 0;
  89.  
  90. /* Set specified routine to be 'woken' up after specified number
  91.  * of ticks (allows CPU to be freed up and reminders posted);
  92.  */
  93. static void
  94. dr_wake(hp, rx_or_tx, routine, ticks)
  95. struct drchan *hp;
  96. int rx_or_tx;
  97. void (*routine) __ARGS((struct drchan *));
  98. int ticks;
  99. {
  100.     hp->w[rx_or_tx].wcall = routine;
  101.     hp->w[rx_or_tx].wakecnt = ticks;
  102. }
  103.  
  104. /* Master interrupt handler.  One interrupt at a time is handled.
  105.  * here. Service routines are called from here.
  106.  */
  107. void
  108. drint(dev)
  109. int dev;
  110. {
  111.     char st;
  112.     int16 i;
  113.     int16 pcbase = Drsi[dev].addr;
  114.     struct drchan *hpa = &Drchan[2 * dev];
  115.     struct drchan *hpb = &Drchan[(2 * dev)+1];
  116.  
  117.     Drsi[dev].ints++;
  118.  
  119. yuk:
  120.     /* Check CTC for timer interrupt */
  121.     st = read_ctc(pcbase, Z8536_CSR3);
  122.     if(st & Z_IP){
  123.         /* Reset interrupt pending */
  124.         write_ctc(pcbase, Z8536_CSR3, Z_CIP|Z_GCB);
  125.         for(i = 0; i <= 1; i++) {
  126.             if(hpa->w[i].wakecnt) {
  127.                 if(--hpa->w[i].wakecnt == 0) {
  128.                     (hpa->w[i].wcall)(hpa);
  129.                 }
  130.             }
  131.             if(hpb->w[i].wakecnt){
  132.                 if(--hpb->w[i].wakecnt == 0) {
  133.                     (hpb->w[i].wcall)(hpb);
  134.                 }
  135.             }
  136.         }
  137.     }
  138.     /* Check the SIO for interrupts */
  139.  
  140.     /* Read interrupt status register from channel A */
  141.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0){
  142.         /* Use IFs to process ALL interrupts pending
  143.          * because we need to check all interrupt conditions
  144.          */
  145.         if(st & CHARxIP){
  146.             /* Channel A Rcv Interrupt Pending */
  147.             rx_fsm(hpa);
  148.         }
  149.         if(st & CHBRxIP){
  150.             /* Channel B Rcv Interrupt Pending */
  151.             rx_fsm(hpb);
  152.         }
  153.         if(st & CHATxIP){
  154.             /* Channel A Transmit Int Pending */
  155.             tx_fsm(hpa);
  156.         }
  157.         if(st & CHBTxIP){
  158.             /* Channel B Transmit Int Pending */
  159.             tx_fsm(hpb);
  160.         }
  161.         if(st & CHAEXT){
  162.             /* Channel A External Status Int */
  163.             drexint(hpa);
  164.         }
  165.         if(st & CHBEXT){
  166.             /* Channel B External Status Int */
  167.             drexint(hpb);
  168.         }
  169.         /* Reset highest interrupt under service */
  170.         write_scc(hpa->base+CTL,R0,RES_H_IUS);
  171.  
  172.     } /* End of while loop on int processing */
  173.     if(read_ctc(pcbase, Z8536_CSR3) & Z_IP)
  174.         goto yuk;
  175. }
  176.  
  177.  
  178. /* DRSI SIO External/Status interrupts
  179.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  180.  * Receiver automatically goes to Hunt on an abort.
  181.  *
  182.  * If the Tx Underrun interrupt hits, change state and
  183.  * issue a reset command for it, and return.
  184.  */
  185. static void
  186. drexint(hp)
  187. struct drchan *hp;
  188. {
  189.     int base = hp->base;
  190.     int i_state = dirps();                                  /* disable interrupts */
  191.     char st = read_scc(base+CTL,R0);        /* Fetch status */
  192.  
  193.     hp->exints++;
  194.  
  195.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  196.     /* Note that the TxEOM bit remains set once we go    */
  197.     /* back to receive.  The following qualifications    */
  198.     /* are necessary to prevent an aborted frame causing */
  199.     /* a queued transmit frame to be tossed when in      */
  200.     /* DEFER state on transmit.                          */
  201.     if((hp->tstate != DEFER) && (hp->rstate==0) && (st & TxEOM)){
  202.         if(hp->tstate != UNDERRUN){
  203.             /* This is an unexpected underrun.  Discard the current
  204.              * frame (there's no way to rewind),  kill the transmitter
  205.              * and return to receive with a wakeup posted to get the
  206.              * next (if any) frame.  Any recovery will have to be done
  207.              * by higher level protocols (yuk).
  208.              */
  209.             write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  210.             write_scc(base, R1, 0);         /* Prevent ext.status int */
  211.             write_scc(base, R0, RES_Tx_P);  /* Reset Tx int pending */
  212.             write_scc(base, R0, ERR_RES);
  213.             write_scc(base, R0, RES_EOM_L); /* Reset underrun latch */
  214.             free_p(hp->sndbuf);
  215.             hp->tstate = IDLE;
  216.             hp->tx_state = drtx_idle;
  217.             dr_wake(hp, TX, tx_fsm, hp->params[SLOTIME]);
  218.             hp->rstate = ENABLE;
  219.             hp->rx_state = drrx_enable;
  220.             drrx_enable(hp);
  221.         }
  222.     }
  223.     /* Receive Mode only
  224.      * This triggers when hunt mode is entered, & since an ABORT
  225.      * automatically enters hunt mode, we use that to clean up
  226.      * any waiting garbage
  227.      */
  228.     if((hp->rstate != IDLE) && (st & BRK_ABRT)){
  229.         if(hp->rcvbuf != NULLBUF){
  230.             hp->rcp = hp->rcvbuf->data;
  231.             hp->rcvbuf->cnt = 0;
  232.         }
  233.         while(read_scc(base,R0) & Rx_CH_AV)
  234.             (void) inportb(base+DATA);
  235.         hp->aborts++;
  236.         hp->rstate = ACTIVE;
  237.         write_scc(base, R0, ERR_RES);
  238.     }
  239.     /* reset external status latch */
  240.     write_scc(base,R0,RES_EXT_INT);
  241.     restore(i_state);
  242. }
  243.  
  244. /* Receive Finite State Machine - dispatcher */
  245. static void
  246. rx_fsm(hp)
  247. struct drchan *hp;
  248. {
  249.     int i_state = dirps();
  250.  
  251.     hp->rxints++;
  252.     (*hp->rx_state)(hp);
  253.     restore(i_state);
  254. }
  255.  
  256. /* drrx_enable
  257.  * Receive ENABLE state processor
  258.  */
  259. static void
  260. drrx_enable(hp)
  261. struct drchan *hp;
  262. {
  263.     int16 base = hp->base;
  264.  
  265.     write_scc(base, R1, INT_ALL_Rx|EXT_INT_ENAB);
  266.     write_scc(base, R15, BRKIE);    /* Allow ABORT Int */
  267.     write_scc(base, R14, BRSRC|BRENABL|SEARCH);
  268.     /* Turn on rx and enter hunt mode */
  269.     write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  270.  
  271.     if(hp->rcvbuf != NULLBUF){
  272.         hp->rcvbuf->cnt = 0;
  273.         hp->rcp = hp->rcvbuf->data;
  274.     }
  275.     hp->rstate = ACTIVE;
  276.     hp->rx_state = drrx_active;
  277. }
  278.  
  279. /* drrx_active
  280.  * Receive ACTIVE state processor
  281.  */
  282. static void
  283. drrx_active(hp)
  284. struct drchan *hp;
  285. {
  286.     int16 base = hp->base;
  287.     unsigned char rse,st;
  288.     struct phdr *phdr;
  289.     struct mbuf *bp;
  290.  
  291.     /* Allocate a receive buffer if not already present */
  292.     if(hp->rcvbuf == NULLBUF){
  293.         bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  294.         if(bp == NULLBUF){
  295.             /* No buffer - abort the receiver */
  296.             write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  297.             /* Clear character from rx buffer in SIO */
  298.             (void) inportb(base+DATA);
  299.             return;
  300.         }
  301.         hp->rcvbuf->cnt = 0;
  302.         hp->rcp = hp->rcvbuf->data;
  303.     }
  304.  
  305.     st = read_scc(base, R0); /* get interrupt status from R0 */
  306.     rse = read_scc(base,R1); /* get special status from R1 */
  307.  
  308.     if(st & Rx_CH_AV){
  309.         /* there is a char to be stored
  310.          * read special condition bits before reading the data char
  311.          * (already read above)
  312.          */
  313.         if(rse & Rx_OVR){
  314.             /* Rx overrun - toss buffer */
  315.             hp->rcp = hp->rcvbuf->data;     /* reset buffer pointers */
  316.             hp->rcvbuf->cnt = 0;
  317.             hp->rstate = RXERROR;   /* set error flag */
  318.             hp->rovers++;           /* count overruns */
  319.         } else if(hp->rcvbuf->cnt >= hp->bufsiz){
  320.             /* Too large -- toss buffer */
  321.             hp->toobig++;
  322.             hp->rcp = hp->rcvbuf->data;     /* reset buffer pointers */
  323.             hp->rcvbuf->cnt = 0;
  324.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  325.         }
  326.         /* ok, we can store the received character now */
  327.         if((hp->rstate == ACTIVE) && ((st & BRK_ABRT) == 0)){
  328.             *hp->rcp++ = inportb(base+DATA); /* char to rcv buff */
  329.             hp->rcvbuf->cnt++;               /* bump count */
  330.         } else {
  331.             /* got to empty FIFO */
  332.             (void) inportb(base+DATA);
  333.             hp->rcp = hp->rcvbuf->data;     /* reset buffer pointers */
  334.             hp->rcvbuf->cnt = 0;
  335.             hp->rstate = RXABORT;
  336.             write_scc(base,R0,ERR_RES);     /* reset err latch */
  337.         }
  338.     }
  339.     /* The End of Frame bit is ALWAYS associated with a character,
  340.      * usually, it is the last CRC char.  Only when EOF is true can
  341.      * we look at the CRC byte to see if we have a valid frame
  342.      */
  343.     if(rse & END_FR){
  344.         hp->rxframes++;
  345.         /* END OF FRAME -- Make sure Rx was active */
  346.         if(hp->rcvbuf->cnt > 0){        /* any data to store */
  347.             /* looks like a frame was received
  348.              * now is the only time we can check for CRC error
  349.              */
  350.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) ||
  351.              (hp->rcvbuf->cnt < 10) || (st & BRK_ABRT)){
  352.                 /* error occurred; toss frame */
  353.                 if(rse & CRC_ERR)
  354.                     hp->crcerr++;   /* count CRC errs */
  355.                 hp->rcp = hp->rcvbuf->data;
  356.                 hp->rcvbuf->cnt = 0;
  357.                 hp->rstate = ACTIVE;   /* Clear error state */
  358.             } else {
  359.                 /* Here we have a valid frame */
  360.                 bp = alloc_mbuf(sizeof(struct phdr));
  361.                 bp->cnt = sizeof(struct phdr);
  362.                 phdr = (struct phdr *)bp->data;
  363.                 phdr->type = CL_AX25;
  364.                 phdr->iface = hp->iface;
  365.                 bp->next = hp->rcvbuf;
  366.                 hp->rcvbuf->cnt -= 2;    /* chuck FCS bytes */
  367.                 enqueue(&Hopper, bp);    /* queue it in */
  368.                 hp->enqueued++;
  369.                 /* packet queued - reset buffer pointer */
  370.                 hp->rcvbuf = NULLBUF;
  371.             } /* end good frame queued */
  372.         }  /* end check for active receive upon EOF */
  373.     }
  374. }
  375.  
  376. /*
  377.  * TX finite state machine - dispatcher
  378.  */
  379. static void
  380. tx_fsm(hp)
  381. struct drchan *hp;
  382. {
  383.     int i_state = dirps();
  384.  
  385.     if(hp->tstate != DEFER && hp->tstate)
  386.         hp->txints++;
  387.     (*hp->tx_state)(hp);
  388.     restore(i_state);
  389. }
  390.  
  391. /* drtx_idle
  392.  * Transmit IDLE transmit state processor
  393.  */
  394. static void
  395. drtx_idle(hp)
  396. struct drchan *hp;
  397. {
  398.     int16 base;
  399.  
  400.     /* Tx idle - is there a frame to transmit ? */
  401.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  402.         /* Nothing to send - return to receive mode
  403.          * Turn Tx off - any trailing flag should have been sent
  404.          * by now
  405.          */
  406. #ifdef DRSIDEBUG
  407.         tputs("Nothing to TX\n");
  408. #endif
  409.         base = hp->base;
  410.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  411.         write_scc(base, R0, ERR_RES);   /* Reset error bits */
  412.  
  413.         /* Delay for squelch tail before enabling receiver */
  414.         hp->rstate = ENABLE;
  415.         hp->rx_state = drrx_enable;
  416.         dr_wake(hp, RX, rx_fsm, hp->params[SQUELDELAY]);
  417.     } else {
  418.         /* Frame to transmit */
  419.         hp->tstate = DEFER;
  420.         hp->tx_state = drtx_defer;
  421.         drtx_defer(hp);
  422.     }
  423. }
  424.  
  425. /* drtx_defer
  426.  * Transmit DEFER state processor
  427.  */
  428. static void
  429. drtx_defer(hp)
  430. struct drchan *hp;
  431. {
  432.     int16 base = hp->base;
  433.  
  434.     if ( hp->params[FULLDUP] )      /* if we are running fullduplex */
  435.         goto transmit;          /* then just fire away          */
  436.  
  437.     /* We may have defered a previous tx attempt - in any event...
  438.      * Check DCD in case someone is already transmitting
  439.      * then check to see if we should defer due to P-PERSIST.
  440.      */
  441. #ifdef DRSIDEBUG
  442.     tputs("drtx_defer - checking for DCD\n");
  443. #endif
  444.     if((read_scc(base+CTL, R0) & DCD) > 0){
  445.         /* Carrier detected - defer */
  446.         hp->txdefers++;
  447.         dr_wake(hp, TX, tx_fsm, 10);    /* Defer for 100 mS */
  448. #ifdef DRSIDEBUG
  449.         tputs("drtx_defer - TX deferred\n");
  450. #endif
  451.         return;
  452.     }
  453.  
  454. #ifdef DRSIDEBUG
  455.     tputs("drtx_defer - checking for P-PERSIST backoff\n");
  456. #endif
  457.     /* P-PERSIST is checked against channel 3 of the 8536 which is
  458.      * the free running counter for the 10 mS tick; The counter
  459.      * goes through 0x6000 ticks per 10 mS or one tick every
  460.      * 407 nS - this is pretty random compared to the DOS time of
  461.      * day clock (0x40:0x6C) used by the other (EAGLE) drivers.
  462.      */
  463.     if (hp->params[PERSIST] <= read_ctc(base,Z8536_CC3LSB)) {
  464. #ifdef DRSIDEBUG
  465.         tputs("drtx_defer - BACKOFF\n");
  466. #endif
  467.         hp->txppersist++;
  468.         dr_wake (hp, TX, tx_fsm, hp->params[SLOTIME]);
  469.         return;
  470.     }
  471. transmit:
  472.     /* No backoff - set RTS and start to transmit frame */
  473.     write_scc(base, R1, 0);         /* Prevent external status int */
  474.     write_scc(base, R3, Rx8);       /* Turn Rx off */
  475.     hp->rstate = IDLE;              /* Mark Rx as idle */
  476.     hp->tstate = RRTS;
  477.     hp->tx_state = drtx_rrts;
  478. #ifdef DRSIDEBUG
  479.     tputs("drtx_defer - wake posted for drtx_rrts\n");
  480. #endif
  481.     write_scc(base, R9, 0);         /* Interrupts off */
  482.     write_scc(base,R5,RTS|Tx8|DTR); /* Turn tx on */
  483.     dr_wake(hp, TX, tx_fsm, 10);
  484. }
  485.  
  486. /* drtx_rrts
  487.  * Transmit RRTS state processor
  488.  */
  489. static void
  490. drtx_rrts(hp)
  491. struct drchan *hp;
  492. {
  493.     int16 base = hp->base;
  494.  
  495.     write_scc(base, R9, 0); /* Interrupts off */
  496.     write_scc(base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);       /* Tx now on */
  497.     hp->tstate = TFIRST;
  498.     hp->tx_state = drtx_tfirst;
  499. #ifdef DRSIDEBUG
  500.     tputs("8530 Int status %x\n", read_scc(base+CHANA,R3));
  501.     tputs("drtx_rrts - Wake posted for TXDELAY\n");
  502. #endif
  503.     dr_wake(hp, TX, tx_fsm, hp->params[TXDELAY]);
  504. }
  505.  
  506. /* drtx_tfirst
  507.  * Transmit TFIRST state processor
  508.  */
  509. static void
  510. drtx_tfirst(hp)
  511. struct drchan *hp;
  512. {
  513.     int16 base = hp->base;
  514.     char c;
  515.  
  516.     /* Copy data to a local buffer to save on mbuf overheads
  517.      * during transmit interrupt time.
  518.      */
  519.     hp->drtx_cnt = len_p(hp->sndbuf);
  520.     hp->drtx_tcp = hp->drtx_buffer;
  521.  
  522.     pullup(&hp->sndbuf, hp->drtx_tcp, hp->drtx_cnt);
  523.  
  524.     /* Transmit the first character in the buffer */
  525.     c = *hp->drtx_tcp++;
  526.     hp->drtx_cnt--;
  527.  
  528.     write_scc(base, R0, RES_Tx_CRC);        /* Reset CRC */
  529.     write_scc(base, R0, RES_EOM_L);         /* Reset underrun latch */
  530.     outportb(base+DATA, c);                 /* Output first character */
  531.     write_scc(base, R15, TxUIE);            /* Allow underrun ints only */
  532.     write_scc(base, R1, TxINT_ENAB|EXT_INT_ENAB); /* Tx/Ext status ints on */
  533.     write_scc(base, R9, MIE|NV);            /* master enable */
  534.     hp->tstate = ACTIVE;
  535.     hp->tx_state = drtx_active;
  536. }
  537.  
  538. /* drtx_active
  539.  * Transmit ACTIVE state processor
  540.  */
  541. static void
  542. drtx_active(hp)
  543. struct drchan *hp;
  544. {
  545.     if(hp->drtx_cnt-- > 0){
  546.         /* Send next character */
  547.         outportb(hp->base+DATA, *hp->drtx_tcp++);
  548.     } else {
  549.         /* No more to send - wait for underrun to hit */
  550.         hp->tstate = UNDERRUN;
  551.         hp->tx_state = drtx_flagout;
  552.         free_p(hp->sndbuf);
  553.         write_scc(hp->base, R0, RES_EOM_L);  /* Send CRC on underrun */
  554.         write_scc(hp->base, R0, RES_Tx_P);   /* Reset Tx Int pending */
  555.     }
  556. }
  557.  
  558. /* drtx_flagout
  559.  * Transmit FLAGOUT state processor
  560.  */
  561. static void
  562. drtx_flagout(hp)
  563. struct drchan *hp;
  564. {
  565.     /* Arrive here after CRC sent and Tx interrupt fires.
  566.      * Post a wake for ENDDELAY
  567.      */
  568.  
  569.     hp->tstate = UNDERRUN;
  570.     hp->tx_state = drtx_downtx;
  571.     write_scc(hp->base, R9, 0);
  572.     write_scc(hp->base, R0,  RES_Tx_P);
  573.     dr_wake(hp, TX, tx_fsm, hp->params[ENDDELAY]);
  574. }
  575.  
  576. /* drtx_downtx
  577.  * Transmit DOWNTX state processor
  578.  */
  579. static void
  580. drtx_downtx(hp)
  581. struct drchan *hp;
  582. {
  583.     int base = hp->base;
  584.  
  585.     /* See if theres anything left to send - if there is,  send it ! */
  586.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  587.         /* Nothing left to send - return to receive */
  588.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  589.         write_scc(base, R0, ERR_RES);   /* Reset error bits */
  590.         hp->tstate = IDLE;
  591.         hp->tx_state = drtx_idle;
  592.         hp->rstate = ENABLE;
  593.         hp->rx_state = drrx_enable;
  594.         drrx_enable(hp);
  595.     } else
  596.         drtx_tfirst(hp);
  597.  
  598. }
  599.  
  600. /* Write CTC register */
  601. static void
  602. write_ctc(port, reg, val)
  603. unsigned port,reg,val;
  604. {
  605.     int16 base = port;
  606.     int i_state = dirps();
  607.  
  608.     /* Select register */
  609.     outportb(base+Z8536_MASTER,(char)reg);
  610.     outportb(base+Z8536_MASTER,(char)val);
  611.     restore(i_state);
  612. }
  613.  
  614. /* Read CTC register */
  615. static char
  616. read_ctc(port, reg)
  617. unsigned port, reg;
  618. {
  619.     int16 i, base = port;
  620.     char c;
  621.     int i_state = dirps();
  622.  
  623.     /* Select register */
  624.     outportb(base+Z8536_MASTER,(char)(reg&0xFF));
  625.     /* Delay for a short time to allow 8536 to settle */
  626.     for(i=0;i<100;i++);
  627.     c = inportb(base+Z8536_MASTER);
  628.     restore(i_state);
  629.     return(c&0xFF);
  630. }
  631.  
  632. /* Initialize dr controller parameters */
  633. static int
  634. drchanparam(hp)
  635. struct drchan *hp;
  636. {
  637.     int16 tc;
  638.     long br;
  639.  
  640.     /* Initialize 8530 channel for SDLC operation */
  641.     int16 base = hp->base;
  642.     int i_state = dirps();
  643.  
  644.     switch(base & 2){
  645.     case 2:
  646.         write_scc(base,R9,CHRA);        /* Reset channel A */
  647.         break;
  648.     case 0:
  649.         write_scc(base,R9,CHRB);        /* Reset channel B */
  650.         break;
  651.     }
  652.     /* Deselect all Rx and Tx interrupts */
  653.     write_scc(base,R1,0);
  654.  
  655.     /* Turn off external interrupts (like CTS/CD) */
  656.     write_scc(base,R15,0);
  657.  
  658.     /* X1 clock, SDLC mode */
  659.     write_scc(base,R4,SDLC|X1CLK);   /* SDLC mode and X1 clock */
  660.  
  661.     /* Now some misc Tx/Rx parameters */
  662.     /* CRC PRESET 1, NRZI Mode */
  663.     write_scc(base,R10,CRCPS|NRZI);
  664.  
  665.     /* Set up BRG and DPLL multiplexers */
  666.     /* Tx Clk from RTxC. Rcv Clk from DPLL, TRxC pin outputs BRG */
  667.     write_scc(base,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCBR);
  668.  
  669.     /* Null out SDLC start address */
  670.     write_scc(base,R6,0);
  671.  
  672.     /* SDLC flag */
  673.     write_scc(base,R7,FLAG);
  674.  
  675.     /* Set up the Transmitter but don't enable it */
  676.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  677.     write_scc(base,R5,Tx8|DTR);
  678.  
  679.     /* Receiver - initial setup only - more later */
  680.     write_scc(base,R3,Rx8);          /* 8 bits/char */
  681.  
  682.     /* Setting up BRG now - turn it off first */
  683.     write_scc(base,R14,BRSRC);     /* BRG off, but keep Pclk source */
  684.  
  685.     /* set the 32x time constant for the BRG */
  686.  
  687.     br = hp->speed;                 /* get desired speed */
  688.     tc = ((XTAL/32)/br)-2;          /* calc 32X BRG divisor */
  689.  
  690.     write_scc(base,R12,tc&0xFF);      /* lower byte */
  691.     write_scc(base,R13,(tc>>8)&0xFF); /* upper bite */
  692.  
  693.     /* Time to set up clock control register for RECEIVE mode
  694.      * DRSI has xtal osc going to pclk at 4.9152 Mhz
  695.      * The BRG is sourced from that, and set to 32x clock
  696.      * The DPLL is sourced from the BRG.  BRG is fed to the TRxC pin
  697.      * Transmit clock is provided by the BRG externally divided by
  698.      * 32 in the CTC counter 1 and 2.
  699.      * Receive clock is from the DPLL
  700.      */
  701.  
  702.     /* Following subroutine sets up and ENABLES the receiver */
  703.     drrx_enable(hp);
  704.     
  705.     /* DPLL from BRG, BRG source is PCLK */
  706.     write_scc(hp->base,R14,BRSRC|SSBR);
  707.     /* SEARCH mode, keep BRG source */
  708.     write_scc(hp->base,R14,BRSRC|SEARCH);
  709.     /* Enable the BRG */
  710.     write_scc(hp->base,R14,BRSRC|BRENABL);
  711.  
  712.     /* enable the receive interrupts */
  713.  
  714.     write_scc(hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  715.     write_scc(hp->base,R15,BRKIE);  /* ABORT int */
  716.     write_scc(hp->base,R9,MIE|NV);  /* master enable */
  717.  
  718.  
  719.     /* Now, turn on the receiver and hunt for a flag */
  720.     write_scc(hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  721.  
  722.     restore(i_state);
  723.     return 0;
  724. }
  725.  
  726. /*
  727.  * Initialize the CTC (8536)
  728.  * Only the counter/timers are used - the IO ports are un-comitted.
  729.  * Channels 1 and 2 are linked to provide a /32 counter to convert
  730.  * the SIO BRG to a real clock for Transmit clocking.
  731.  * CTC 3 is left free running on a 10 mS period.  It is always polled
  732.  * and therefore all interrupts from the chip are disabled.
  733.  *
  734.  * Updated 02/16/89 by N6TTO
  735.  * Changed to support the use of the second channel on the 8530.
  736.  * Added so that the driver works on the DRSI type 2 PC Adaptor
  737.  * which has 2 1200 bps modems.
  738.  *
  739.  */
  740. static void
  741. drinitctc(port)
  742. unsigned port;
  743. {
  744.     long i;
  745.  
  746.     /* Initialize 8536 CTC */
  747.  
  748.     /* Initialize 8536 */
  749.     /* Start by forcing chip into known state */
  750.     (void) read_ctc(port, Z8536_MICR);
  751.  
  752.     write_ctc(port, Z8536_MICR, 0x01);      /* Reset the CTC */
  753.     for(i=0;i < 1000L; i++)         /* Loop to delay */
  754.         ;
  755.     write_ctc(port, Z8536_MICR, 0x00);      /* Clear reset and start init seq. */
  756.  
  757.     /* Wait for chip to come ready */
  758.     while((read_ctc(port, Z8536_MICR)) != (char) 0x02)
  759.         ;
  760.  
  761.     write_ctc(port, Z8536_MICR, 0xa6);      /* MIE|NV|CT_VIS|RJA */
  762.     write_ctc(port, Z8536_MCCR, 0xf4);      /* PBE|CT1E|CT2E|CT3E|PAE */
  763.  
  764.     write_ctc(port, Z8536_CTMS1, 0xe2);     /* Continuous,EOE,ECE, Pulse output */
  765.     write_ctc(port, Z8536_CTMS2, 0xe2);     /* Continuous,EOE,ECE, Pulse output */
  766.     write_ctc(port, Z8536_CTMS3, 0x80);     /* Continuous,Pulse output */
  767.     write_ctc(port, Z8536_CT1MSB, 0x00);    /* Load time constant CTC #1 */
  768.     write_ctc(port, Z8536_CT1LSB, 0x10);
  769.     write_ctc(port, Z8536_CT2MSB, 0x00);    /* Load time constant CTC #2 */
  770.     write_ctc(port, Z8536_CT2LSB, 0x10);
  771.     write_ctc(port, Z8536_CT3MSB, 0x60);    /* Load time constant CTC #3 */
  772.     write_ctc(port, Z8536_CT3LSB, 0x00);
  773.  
  774.     write_ctc(port, Z8536_IVR, 0x06);
  775.  
  776.     /* Set port direction bits in port A and B
  777.      * Data is input on bits d1 and d5, output on d0 and d4.
  778.      * The direction is set by 1 for input and 0 for output
  779.      */
  780.     write_ctc(port, Z8536_PDCA, 0x22);
  781.     write_ctc(port, Z8536_PDCB, 0x22);
  782.  
  783.     write_ctc(port, Z8536_CSR1, Z_GCB|Z_TCB);  /* Start CTC #1 running */
  784.     write_ctc(port, Z8536_CSR2, Z_GCB|Z_TCB);  /* Start CTC #2 running */
  785.     write_ctc(port, Z8536_CSR3, Z_IE|Z_GCB|Z_TCB); /* Start CTC #3 running */
  786. }
  787.  
  788. /* Attach a DRSI interface to the system
  789.  * argv[0]: hardware type, must be "drsi"
  790.  * argv[1]: I/O address, e.g., "0x300"
  791.  * argv[2]: vector, e.g., "2"
  792.  * argv[3]: mode, must be:
  793.  *          "ax25" (AX.25 UI frame format)
  794.  * argv[4]: iface label, e.g., "dr0"
  795.  * argv[5]: receiver packet buffer size in bytes
  796.  * argv[6]: maximum transmission unit, bytes
  797.  * argv[7]: iface speed for channel A
  798.  * argv[8]: iface speed for channel B (defaults to same as A if absent)
  799.  * argv[9]: First IP address, optional (defaults to Ip_addr)
  800.  * argv[10]: Second IP address, optional (defaults to Ip_addr)
  801.  */
  802. int
  803. dr_attach(argc,argv)
  804. int argc;
  805. char *argv[];
  806. {
  807.     struct iface *if_pca,*if_pcb;
  808.     struct drchan *hp;
  809.     int dev;
  810.  
  811.     /* Quick check to make sure args are good and mycall is set */
  812.     if(*Mycall == '\0'){
  813.         tputs(Nomycall);
  814.         return -1;
  815.     }
  816.     if(strcmp(argv[3],"ax25") != 0){
  817.         tputs("Mode must be 'ax25'\n");
  818.         return -1;
  819.     }
  820.     if(if_lookup(argv[4]) != NULLIF) {
  821.         tprintf(Ifexist,argv[4]);
  822.         return -1;
  823.     }
  824.     /* Note: More than one card can be supported if you give up a COM:
  825.      * port, thus freeing up an IRQ line and port address
  826.      */
  827.     if(Drnbr >= DRMAX){
  828.         tprintf("Max %d DRSI controllers\n",DRMAX);
  829.         return -1;
  830.     }
  831.     dev = Drnbr++;
  832.  
  833.     /* Initialize hardware-level control structure */
  834.     Drsi[dev].addr = htoi(argv[1]);
  835.     Drsi[dev].vec = htoi(argv[2]);
  836.  
  837.     /* Save original interrupt vector */
  838.     Drsi[dev].oldvec = getirq(Drsi[dev].vec);
  839.  
  840.     /* Set new interrupt vector */
  841.     if(setirq(Drsi[dev].vec,Drhandle[dev]) == -1){
  842.         tprintf("IRQ %u out of range\n",Drsi[dev].vec);
  843.         Drnbr--;
  844.     }
  845.     /* Initialize the CTC */
  846.     drinitctc(Drsi[dev].addr);
  847.  
  848.     /* Create iface structures and fill in details */
  849.     if_pca = (struct iface *)mxallocw(sizeof(struct iface));
  850.     if_pcb = (struct iface *)mxallocw(sizeof(struct iface));
  851.  
  852.     if_pca->addr = if_pcb->addr = Ip_addr;
  853.     if(argc > 9)
  854.         if_pca->addr = resolve(argv[9]);
  855.     if(argc > 10)
  856.         if_pcb->addr = resolve(argv[10]);
  857.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  858.         tprintf(Noipaddr);
  859.         xfree((char *)if_pca);
  860.         xfree((char *)if_pcb);
  861.         Drnbr--;
  862.         return -1;
  863.     }
  864.     /* Append "a" and "b" to iface name */
  865.     if_pca->name = strxdup(argv[4]);
  866.     if_name(if_pca,"a");
  867.     if_pcb->name = strxdup(argv[4]);
  868.     if_name(if_pcb,"b");
  869.  
  870.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  871.     if_pcb->type = if_pca->type = CL_AX25;
  872.     if_pcb->ioctl = if_pca->ioctl = dr_ctl;
  873.     if_pca->dev = 2*dev;                    /* dr0a */
  874.     if_pcb->dev = 2*dev + 1;                /* dr0b */
  875.     if_pcb->stop = if_pca->stop = dr_stop;
  876.     if_pcb->output = if_pca->output = ax_output;
  877.     if_pcb->raw = if_pca->raw = dr_raw;
  878.  
  879.     if_pcb->send = if_pca->send = ax_send;
  880.  
  881.     if_pcb->hwaddr = strxdup(Mycall);
  882.     if_pca->hwaddr = strxdup(Mycall);
  883.  
  884.     /* Link em in to the iface chain */
  885.     if_pca->next = if_pcb;
  886.     if_pcb->next = Ifaces;
  887.     if_pca->niface = Niface++;
  888.     if_pcb->niface = Niface++;
  889.     init_maxheard(if_pca);
  890.     init_maxheard(if_pcb);
  891.     init_flags(if_pca);
  892.     init_flags(if_pcb);
  893.     Ifaces = if_pca;
  894.  
  895.     /* set params in drchan table for CHANNEL B */
  896.  
  897.     hp = &Drchan[2*dev+1];                          /* dr1 is offset 1 */
  898.     hp->iface = if_pcb;
  899.     hp->stata = Drsi[dev].addr + CHANA + CTL;       /* permanent status */
  900.     hp->statb = Drsi[dev].addr + CHANB + CTL;       /* addrs for CHANA/B*/
  901.     if(argc > 8){
  902.         /* Separate speed for channel B */
  903.         hp->speed = (int16)atoi(argv[8]);
  904.     } else {
  905.         /* Set speed to same as for channel A */
  906.         hp->speed = (int16)atoi(argv[7]);
  907.     }
  908.     hp->base = Drsi[dev].addr + CHANB;
  909.     hp->bufsiz = atoi(argv[5]);
  910.     hp->drtx_buffer = mxallocw(if_pcb->mtu + 100);
  911.     hp->tstate = IDLE;
  912.     hp->tx_state = drtx_idle;
  913.     hp->w[RX].wcall = NULL;
  914.     hp->w[RX].wakecnt = 0;
  915.     hp->w[TX].wcall = NULL;
  916.     hp->w[TX].wakecnt = 0;
  917.     /* default KISS Params */
  918.     hp->params[TXDELAY] = 25;               /* 250 Ms */
  919.     hp->params[PERSIST] = 64;               /* 25% persistence */
  920.     hp->params[SLOTIME] = 10;               /* 100 Ms */
  921.     hp->params[SQUELDELAY] = 20;            /* 200 Ms */
  922.     hp->params[ENDDELAY] = 10;              /* 100 Ms */
  923.     hp->params[FULLDUP] = 0;                /* CSMA */
  924.  
  925.     write_scc(hp->stata,R9,FHWRES);         /* Hardware reset */
  926.  
  927.     /* Disable interrupts with Master interrupt ctrl reg */
  928.     write_scc(hp->stata,R9,0);
  929.  
  930.     drchanparam(hp);
  931.  
  932.     /* Initialize buffer pointers */
  933.     hp->rcvbuf = NULLBUF;
  934.     hp->rcvbuf->cnt = 0;
  935.     hp->sndq = NULLBUF;
  936.  
  937.     /* set params in drchan table for CHANNEL A */
  938.     hp = &Drchan[2*dev];                    /* dr0a is offset 0 */
  939.     hp->iface = if_pca;
  940.     hp->speed = (int16)atoi(argv[7]);
  941.     hp->base = Drsi[dev].addr + CHANA;
  942.     hp->bufsiz = atoi(argv[5]);
  943.     hp->drtx_buffer = mxallocw(if_pca->mtu + 100);
  944.     hp->tstate = IDLE;
  945.     hp->tx_state = drtx_idle;
  946.     hp->w[RX].wcall = NULL;
  947.     hp->w[RX].wakecnt = 0;
  948.     hp->w[TX].wcall = NULL;
  949.     hp->w[TX].wakecnt = 0;
  950.     /* default KISS Params */
  951.     hp->params[TXDELAY] = 30;               /* 300 Ms */
  952.     hp->params[PERSIST] = 64;               /* 25% persistence */
  953.     hp->params[SLOTIME] = 10;               /* 100 Ms */
  954.     hp->params[SQUELDELAY] = 20;            /* 200 Ms */
  955.     hp->params[ENDDELAY] = 10;              /* 100 Ms */
  956.     hp->params[FULLDUP] = 0;                /* CSMA */
  957.  
  958.     drchanparam(hp);
  959.  
  960.     /* Initialize buffer pointers */
  961.     hp->rcvbuf = NULLBUF;
  962.     hp->rcvbuf->cnt = 0;
  963.     hp->sndq = NULLBUF;
  964.  
  965.     write_scc(hp->base,R9,MIE|NV);          /* master interrupt enable */
  966.  
  967.     /* Enable interrupt in 8259 interrupt controller */
  968.     maskon(Drsi[dev].vec);
  969.  
  970.     return 0;
  971. }
  972.  
  973. /* Shut down iface */
  974. static int
  975. dr_stop(iface,tmp)
  976. struct iface *iface;
  977. int tmp;
  978. {
  979.     int16 dev = iface->dev;
  980.  
  981.     if(dev & 1)
  982.         return 0;
  983.  
  984.     dev >>= 1;      /* Convert back into DRSI number */
  985.  
  986.     /* Set 8259 interrupt mask (turn off interrupts) */
  987.     maskoff(Drsi[dev].vec);
  988.  
  989.     /* Restore original interrupt vector */
  990.     setirq(Drsi[dev].vec, Drsi[dev].oldvec);
  991.     Drnbr--;
  992.  
  993.     /* Force hardware reset */
  994.     write_scc(Drsi[dev].addr + CHANA + CTL,R9,FHWRES);
  995.     /* Reset the CTC */
  996.     (void) read_ctc(Drsi[dev].addr, Z8536_MICR);
  997.     write_ctc(Drsi[dev].addr, Z8536_MICR, 0x01);
  998.     return 0;
  999. }
  1000.  
  1001. /* Send raw packet on DRSI card */
  1002. static int
  1003. dr_raw(iface,bp)
  1004. struct iface *iface;
  1005. struct mbuf *bp;
  1006. {
  1007.     char kickflag;
  1008.     struct drchan *hp;
  1009.     int i_state = dirps();
  1010.  
  1011.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  1012.  
  1013.     hp = &Drchan[iface->dev];
  1014.     kickflag = (hp->sndq == NULL) & (hp->sndbuf == NULLBUF);
  1015.     /* clever! flag=1 if something in queue */
  1016.     enqueue(&hp->sndq,bp);
  1017.  
  1018.     if(kickflag)                    /* simulate interrupt to xmit */
  1019.         tx_fsm(hp);                     /* process interrupt */
  1020.  
  1021.     restore(i_state);
  1022.     return 0;
  1023. }
  1024.  
  1025. /* display DRSI Channel stats */
  1026. int
  1027. dodrstat(argc,argv,p)
  1028. int argc;
  1029. char *argv[];
  1030. void *p;
  1031. {
  1032.     int i, j;
  1033.  
  1034.     tputs("DRSI Board Statistics - N6TTO dama.940920\n");
  1035.  
  1036.     for(i = 0; i < DRMAX; i++) {
  1037.         for(j = 0; j < 2; j++) {
  1038.             struct drchan *hp = &Drchan[j + i];
  1039.  
  1040.             tprintf("Channel %s\nRxints  %8ld  Txints  %8ld  Exints  %8ld\n",
  1041.                 hp->iface->name, hp->rxints, hp->txints, hp->exints);
  1042.             tprintf("Enqued  %8ld  Crcerr  %8ld  Aborts  %8ld\n",
  1043.                 hp->enqueued, hp->crcerr, hp->aborts);
  1044.             tprintf("RFrames %8ld  Rxovers %8ld  TooBig  %8ld\n",
  1045.                 hp->rxframes, hp->rovers, hp->toobig);
  1046.             tprintf("Txdefer %8ld  Txppers %8ld  Nomem   %8ld\n",
  1047.                 hp->txdefers, hp->txppersist, hp->nomem);
  1048.             tprintf("TxState %8d  RxState %8d\n\n",
  1049.                 hp->tstate,hp->rstate);
  1050.         }
  1051.     }
  1052.     return 0;
  1053. }
  1054.  
  1055. /* Subroutine to set kiss params in channel tables */
  1056. static int
  1057. dr_ctl(iface,argc,argv)
  1058. struct iface *iface;
  1059. int argc;
  1060. char *argv[];
  1061. {
  1062.     int p, v;
  1063.     struct drchan *hp = &Drchan[iface->dev];
  1064.  
  1065.     if(argc < 2){
  1066.         /* If called with less than the required # of parameters
  1067.          * - dump the current values.
  1068.          */
  1069.         for(p = 0;p < CCP_COUNT; p++) {
  1070.             switch(p){
  1071.             case TXDELAY:
  1072.                 tprintf("TxDelay %d\n", hp->params[p]);
  1073.                 break;
  1074.             case PERSIST:
  1075.                 tprintf("Persistence %d\n", hp->params[p]);
  1076.                 break;
  1077.             case SLOTIME:
  1078.                 tprintf("SlotTime %d\n", hp->params[p]);
  1079.                 break;
  1080.             case SQUELDELAY:
  1081.                 tprintf("Squelch delay %d\n", hp->params[p]);
  1082.                 break;
  1083.             case ENDDELAY:
  1084.                 tprintf("TxTail %d\n", hp->params[p]);
  1085.                 break;
  1086.             case FULLDUP:
  1087.                 tprintf("Fullduplex %s\n",
  1088.                   hp->params[p] ? "ON" : "OFF");
  1089.             default:
  1090.                 break;
  1091.             }
  1092.         }
  1093.         tprintf("Speed (bps) %d\n", hp->speed);
  1094.         return 0;
  1095.     }
  1096.  
  1097.     if((p = atoi(argv[0])) > CCP_COUNT) {           /* parameter in binary */
  1098.         tprintf("Parameter %d out of range\n",p);
  1099.         return 1;
  1100.     }
  1101.     v = (int16)atoi(argv[1]);       /* value to be loaded */
  1102.     hp->params[p] = v;                      /* Stuff in Kiss array */
  1103.     return 0;
  1104. }
  1105.  
  1106. #endif /* DRSI */